package com.azu.bitmapworker.common;

import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.SystemClock;

import com.azu.bitmapworker.core.BitmapCache;
import com.azu.bitmapworker.core.BitmapDisplayConfig;
import com.azu.bitmapworker.core.BitmapProcessor;
import com.azu.bitmapworker.utils.Utils;

import java.io.FileDescriptor;
import java.io.InputStream;

/**
 * Created by zhangmian on 14-1-16.
 */
public class CommonBitmapProcessor implements BitmapProcessor {

	private static final int ATTEMPT_COUNT_TO_DECODE_BITMAP = 3;

	@Override
	public Result process(FileDescriptor fileDescriptor, BitmapDisplayConfig config, BitmapCache cache) {
		Bitmap bitmap = decodeSampledBitmapFromDescriptor(fileDescriptor, config.getBitmapWidth(), config.getBitmapHeight(), config.getDecodingOptions(), (CommonBitmapCache)cache);
        Result result = new Result(bitmap, bitmap);
		return result;
	}

	public static Bitmap decodeSampledBitmapFromDescriptor(
			FileDescriptor fileDescriptor, int reqWidth, int reqHeight, BitmapFactory.Options options, CommonBitmapCache cache) {
		BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
		decodeOptions.inJustDecodeBounds = true;
		BitmapFactory.decodeFileDescriptor(fileDescriptor, null, decodeOptions);
		decodeOptions.inSampleSize = calculateInSampleSize(decodeOptions, reqWidth, reqHeight);
		decodeOptions.inPurgeable = options.inPurgeable;
		decodeOptions.inInputShareable = options.inInputShareable;
		decodeOptions.inPreferredConfig = options.inPreferredConfig;
		//利用缓存中保存的Bitmap进行重载,减少了内存回收,再分配的消耗
//		if (Utils.hasHoneycomb()) {
//			addInBitmapOptions(decodeOptions, cache);
//		}

		decodeOptions.inJustDecodeBounds = false;
		Bitmap bitmap = null;
		for (int i = 1; i <= ATTEMPT_COUNT_TO_DECODE_BITMAP; i++) {
			try{
  				bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, decodeOptions);
			}catch (OutOfMemoryError error){
				if(i==1){
					Runtime.getRuntime().gc();
					SystemClock.sleep(2000);
				}else if(i==2){
					cache.clearMemoryCache();
					Runtime.getRuntime().gc();
					SystemClock.sleep(2000);
				}else{
					throw error;
				}
				continue;
			}
			break;
		}
		return bitmap;
//		return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, decodeOptions);
	}

	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	private static synchronized void addInBitmapOptions(BitmapFactory.Options options, CommonBitmapCache cache) {
		// inBitmap only works with mutable bitmaps so force the decoder to
		// return mutable bitmaps.
		options.inMutable = true;

		if (cache != null) {
			// Try and find a bitmap to use for inBitmap
			Bitmap inBitmap = cache.getBitmapFromReusableSet(options);
			if(inBitmap!=null) {
				System.out.println("inBitmap config:" + inBitmap.getConfig());
			}else{
				System.out.println("inBitmap config:null");
			}
			System.out.println("preferred config:"+options.inPreferredConfig);
			if (inBitmap != null && inBitmap.getConfig() == options.inPreferredConfig) {
				options.inBitmap = inBitmap;
			}
		}
	}

	public static int calculateInSampleSize(int width, int height, int reqWidth, int reqHeight) {
		int inSampleSize = 1;
		if (reqWidth == 0 && reqHeight == 0) {
			return inSampleSize;
		}
		if (height > reqHeight || width > reqWidth) {
			if (width > height) {
				inSampleSize = Math.round((float) height / (float) reqHeight);
			} else {
				inSampleSize = Math.round((float) width / (float) reqWidth);
			}
			final float totalPixels = width * height;
			final float totalReqPixelsCap = reqWidth * reqHeight * 2;

			while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
				inSampleSize++;
			}
		}
		return inSampleSize;
	}

	public static int calculateInSampleSizeFromGoogle(int width, int height, int reqWidth, int reqHeight){
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {

			final int halfHeight = height / 2;
			final int halfWidth = width / 2;

			// Calculate the largest inSampleSize value that is a power of 2 and keeps both
			// height and width larger than the requested height and width.
			while ((halfHeight / inSampleSize) > reqHeight
					&& (halfWidth / inSampleSize) > reqWidth) {
				inSampleSize *= 2;
			}

			// This offers some additional logic in example the image has a strange
			// aspect ratio. For example, a panorama may have a much larger
			// width than height. In these cases the total pixels might still
			// end up being too large to fit comfortably in memory, so we should
			// be more aggressive with sample down the image (=larger inSampleSize).

			long totalPixels = width * height / inSampleSize;

			// Anything more than 2x the requested pixels we'll sample down further
			final long totalReqPixelsCap = reqWidth * reqHeight * 2;

			while (totalPixels > totalReqPixelsCap) {
				inSampleSize *= 2;
				totalPixels /= 2;
			}
		}
		return inSampleSize;
	}

	public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
		return calculateInSampleSize(options.outWidth, options.outHeight, reqWidth, reqHeight);
	}

}
